import myStore from "@/store/store"
import { advancedConfigSetting } from "@/assets/js/defaultSettings"

/**
 * 鼠标点击基础样式
 */
class BaseMouseClickStyle {
  constructor() {

  }

  init = () => {

  }

  destroy = () => {

  }
}

class Circle {
  constructor({ origin, speed, color, angle, context }) {
    this.origin = origin
    this.position = { ...this.origin }
    this.color = color
    this.speed = speed
    this.angle = angle
    this.context = context
    this.renderCount = 0
  }

  draw() {
    this.context.fillStyle = this.color
    this.context.beginPath()
    this.context.arc(this.position.x, this.position.y, 2, 0, Math.PI * 2)
    this.context.fill()
  }

  move() {
    this.position.x = (Math.sin(this.angle) * this.speed) + this.position.x
    this.position.y = (Math.cos(this.angle) * this.speed) + this.position.y + (this.renderCount * 0.3)
    this.renderCount++
  }
}

class Boom {
  constructor({ origin, context, circleCount = 10, area }) {
    this.origin = origin
    this.context = context
    this.circleCount = circleCount
    this.area = area
    this.stop = false
    this.circles = []
  }

  randomArray(range) {
    const length = range.length
    const randomIndex = Math.floor(length * Math.random())
    return range[randomIndex]
  }

  randomColor() {
    const range = ['8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
    return '#' + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range) + this.randomArray(range)
  }

  randomRange(start, end) {
    return (end - start) * Math.random() + start
  }

  init() {
    for (let i = 0; i < this.circleCount; i++) {
      const circle = new Circle({
        context: this.context,
        origin: this.origin,
        color: this.randomColor(),
        angle: this.randomRange(Math.PI - 1, Math.PI + 1),
        speed: this.randomRange(1, 6)
      })
      this.circles.push(circle)
    }
  }

  move() {
    this.circles.forEach((circle, index) => {
      if (circle.position.x > this.area.width || circle.position.y > this.area.height) {
        return this.circles.splice(index, 1)
      }
      circle.move()
    })
    if (this.circles.length == 0) {
      this.stop = true
    }
  }

  draw() {
    this.circles.forEach(circle => circle.draw())
  }
}

/**
 * 鼠标点击烟花绽放效果
 */
class MouseClickFireworksStyle extends BaseMouseClickStyle {
  constructor() {
    super()
    this.computerCanvas = document.createElement('canvas');
    this.renderCanvas = document.createElement('canvas');

    this.computerContext = this.computerCanvas.getContext('2d');
    this.renderContext = this.renderCanvas.getContext('2d');

    this.globalWidth = window.innerWidth;
    this.globalHeight = window.innerHeight;

    this.booms = [];
    this.running = false;
  }

  handleMouseDown = (e) => {
    const boom = new Boom({
      origin: { x: e.clientX, y: e.clientY },
      context: this.computerContext,
      area: {
        width: this.globalWidth,
        height: this.globalHeight
      }
    })
    boom.init()
    this.booms.push(boom)
    this.running || this.run()
  }

  handlePageHide = () => {
    this.booms = []
    this.running = false
  }

  init = () => {
    const style = this.renderCanvas.style
    style.position = 'fixed'
    style.top = style.left = 0
    style.zIndex = '999999'
    style.pointerEvents = 'none'

    style.width = this.renderCanvas.width = this.computerCanvas.width = this.globalWidth
    style.height = this.renderCanvas.height = this.computerCanvas.height = this.globalHeight

    document.body.append(this.renderCanvas)

    window.addEventListener('mousedown', this.handleMouseDown.bind(this))
    window.addEventListener('pagehide', this.handlePageHide.bind(this))
    // window.onmousedown = this.handleMouseDown.bind(this)
    // window.onpagehide = this.handlePageHide.bind(this)
  }

  destroy = () => {
    window.removeEventListener('mousedown', this.handleMouseDown.bind(this))
    window.removeEventListener('pagehide', this.handlePageHide.bind(this))
  }

  run = () => {
    this.running = true
    if (this.booms.length == 0) {
      return this.running = false
    }

    requestAnimationFrame(this.run.bind(this))

    this.computerContext.clearRect(0, 0, this.globalWidth, this.globalHeight)
    this.renderContext.clearRect(0, 0, this.globalWidth, this.globalHeight)

    this.booms.forEach((boom, index) => {
      if (boom.stop) {
        return this.booms.splice(index, 1)
      }
      boom.move()
      boom.draw()
    })
    this.renderContext.drawImage(this.computerCanvas, 0, 0, this.globalWidth, this.globalHeight)
  }
}

/**
 * 鼠标点击文本数组展示，一种点击效果的极简实现方式
 */
class MouseClickTextStyle extends BaseMouseClickStyle {
  constructor(textArray) {
    super()
    this.a_idx = 0;
    this.arr = textArray ? textArray : ["❤富强❤", "❤民主❤", "❤文明❤", "❤和谐❤", "❤自由❤", "❤平等❤", "❤公正❤", "❤法治❤", "❤爱国❤", "❤敬业❤", "❤诚信❤", "❤友善❤"];
  }
  /**
   * 返回rgb随机颜色
   * @returns 随机颜色
   */
  randomColor = () => {
    return "rgb(" + (~~(Math.random() * 255)) + "," + (~~(Math.random() * 255)) + "," + (~~(Math
      .random() * 255)) + ")";
  }

  init = () => {
    window.addEventListener("click", this.update)
  }

  update = () => {
    var heart = document.createElement("b"); //创建b元素
    // heart.onselectstart = new Function('event.returnValue=false'); //防止拖动

    document.body.appendChild(heart).innerHTML = this.arr[this.a_idx]; //将b元素添加到页面上
    this.a_idx = (this.a_idx + 1) % this.arr.length;
    heart.style.cssText = "position: fixed;left:-100%;"; //给b元素设置样式

    var f = 16; // 字体大小
    var x = event.clientX - f / 2; // 横坐标
    var y = event.clientY - f; // 纵坐标
    var c = this.randomColor(); // 随机颜色
    var a = 1; // 透明度
    var s = 1.2; // 放大缩小

    var timer = setInterval(function () { //添加定时器
      if (a <= 0) {
        document.body.removeChild(heart);
        clearInterval(timer);
      } else {
        heart.style.cssText = "font-size:16px;cursor: default;position: fixed;color:" +
          c + ";left:" + x + "px;top:" + y + "px;opacity:" + a + ";transform:scale(" +
          s + ");";

        y--;
        a -= 0.016;
        s += 0.002;
      }
    }, 15)
  }

  destroy() {
    window.removeEventListener("click", this.update())
  }
}

/**
 * 基础粒子对象，需重写init与update方法
 */
class BaseParticle {
  constructor(styles) {
    this.initialStyles = styles ? styles : {
      "position": "fixed",
      "display": "block",
      "pointerEvents": "none",
      "z-index": "10000000",
      "fontSize": "16px",
      "will-change": "transform"
    }
  }

  /**
   * 初始化和设置显示内容
   * @param {Number} x x
   * @param {Number} y y
   * @param {String} character 显示文本内容，可为ascii字符、emoji字符等
   */
  init = (x, y, character) => {
    // this.velocity = {
    //   x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
    //   y: (1 + Math.random())
    // }

    // this.lifeSpan = 120 + Math.floor(Math.random() * 60) //ms

    // this.position = { x: x - 20, y: y - 20 }

    // this.element = document.createElement('span')
    // this.element.innerHTML = character
    // this.applyProperties(this.element, this.initialStyles)
    // this.update()
    // document.getElementById("layout-main").appendChild(this.element)
  }

  /**
   * 更新显示内容
   */
  update = () => {
    // this.position.x += this.velocity.x
    // this.position.y += this.velocity.y

    // this.velocity.x += (Math.random() < 0.5 ? -1 : 1) * 2 / 75
    // this.velocity.y -= Math.random() / 400

    // this.lifeSpan--
    // this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px,0) scale(" + (this.lifeSpan / 180) + ") rotate("
    //   + (2 * this.lifeSpan) + "deg)"
  }

  /**
   * 销毁显示内容
   */
  die = () => {
    if (this.element) {
      this.element.parentNode.removeChild(this.element)
    }
  }

  /**
   * Applies css `properties` to an element
   */
  applyProperties = (target, properties) => {
    for (var key in properties) {
      target.style[key] = properties[key]
    }
  }
}
/**
 * 基础鼠标移动样式对象，需重写addParticle方法
 */
class BaseMouseMoveStyle {
  constructor(possibleArray) {
    this.possibleArray = possibleArray ? possibleArray : ["❄️"]
    this.width = window.innerWidth
    this.height = window.innerHeight
    this.cursor = { x: this.width / 2, y: this.width / 2 }
    this.particles = []
  }

  init() {
    // console.info("possibleArray", this.possibleArray)
    this.bindEvents()
    this.loop()
  }

  destroy() {
    this.removeEvents()
    this.endLoop()
    // cancelAnimationFrame(this.animationFrameNumber)
  }

  // Bind events that are needed
  bindEvents() {
    document.addEventListener('mousemove', this.onMouseMove)
    document.addEventListener('touchmove', this.onTouchMove)
    document.addEventListener('touchstart', this.onTouchMove)

    window.addEventListener('resize', this.onWindowResize)
  }

  removeEvents() {
    document.removeEventListener('mousemove', this.onMouseMove)
    document.removeEventListener('touchmove', this.onTouchMove)
    document.removeEventListener('touchstart', this.onTouchMove)

    window.removeEventListener('resize', this.onWindowResize)
  }

  onWindowResize = (e) => {
    this.width = window.innerWidth
    this.height = window.innerHeight
  }

  onTouchMove = (e) => {
    if (e.touches.length > 0) {
      for (var i = 0; i < e.touches.length; i++) {
        this.addParticle(e.touches[i].clientX, e.touches[i].clientY, this.possibleArray[Math.floor(Math.random() * this.possibleArray.length)])
      }
    }
  }

  onMouseMove = (e) => {
    this.cursor.x = e.clientX
    this.cursor.y = e.clientY

    this.addParticle(this.cursor.x, this.cursor.y, this.possibleArray[Math.floor(Math.random() * this.possibleArray.length)])
  }

  addParticle = (x, y, character) => {
    var particle = new BaseParticle()
    particle.init(x, y, character)
    this.particles.push(particle)
  }

  updateParticles = () => {
    // Updated
    for (var i = 0; i < this.particles.length; i++) {
      this.particles[i].update()
    }

    // Remove dead particles
    for (let i = this.particles.length - 1; i >= 0; i--) {
      if (this.particles[i].lifeSpan < 0) {
        this.particles[i].die()
        this.particles.splice(i, 1)
      }
    }
  }

  loop = () => {
    this.animationFrameNumber = requestAnimationFrame(this.loop)
    this.updateParticles()
  }

  endLoop = () => {
    this.updateParticles()
    // cancelAnimationFrame(this.animationFrameNumber)
  }
}

/**
 * FairyDust梦幻粒子对象
 */
class FairyDustParticle extends BaseParticle {
  constructor(styles) {
    super(styles)
    this.character = "*";
    this.lifeSpan = 120; //ms
    this.initialStyles = {
      "position": "fixed",
      "display": "block",
      "pointerEvents": "none",
      "z-index": "10000000",
      "fontSize": "16px",
      "will-change": "transform"
    };
  }

  init = (x, y, color) => {
    this.velocity = {
      x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
      y: 1
    };

    this.position = { x: x - 10, y: y - 20 };
    this.initialStyles.color = color;
    // console.log(color);

    this.element = document.createElement('span');
    this.element.innerHTML = this.character;
    this.applyProperties(this.element, this.initialStyles);
    this.update();

    // document.body.appendChild(this.element);
    document.getElementById("layout-main").appendChild(this.element);
  }

  update = () => {
    this.position.x += this.velocity.x;
    this.position.y += this.velocity.y;
    this.lifeSpan--;

    this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px,0) scale(" + (this.lifeSpan / 120) + ")";
  }
}

/**
 * 鼠标移动梦幻粒子样式
 */
class MouseMoveFairyDustStyle extends BaseMouseMoveStyle {
  constructor(possibleArray) {
    super(possibleArray)
    this.possibleArray = ["#D61C59", "#E7D84B", "#1B8798"]
  }

  addParticle = (x, y, character) => {
    var particle = new FairyDustParticle()
    particle.init(x, y, character)
    this.particles.push(particle)
  }
}

/**
 * Snowflake雪花粒子对象
 */
class SnowflakeParticle extends BaseParticle {
  constructor(styles) {
    super(styles)
    this.initialStyles = {
      "position": "fixed",
      "display": "block",
      "pointerEvents": "none",
      "z-index": "10000000",
      "fontSize": "16px",
      "will-change": "transform"
    };
  }

  init = (x, y, character) => {
    this.velocity = {
      x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
      y: (1 + Math.random())
    }

    this.lifeSpan = 120 + Math.floor(Math.random() * 60) //ms

    this.position = { x: x - 20, y: y - 20 }

    this.element = document.createElement('span');
    this.element.innerHTML = character;
    this.applyProperties(this.element, this.initialStyles);
    this.update();

    document.getElementById("layout-main").appendChild(this.element);
  }

  update = () => {
    this.position.x += this.velocity.x
    this.position.y += this.velocity.y

    this.velocity.x += (Math.random() < 0.5 ? -1 : 1) * 2 / 75
    this.velocity.y -= Math.random() / 400

    this.lifeSpan--
    this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px,0) scale(" + (this.lifeSpan / 180) + ") rotate("
      + (2 * this.lifeSpan) + "deg)"
  }
}

/**
 * 鼠标移动雪花粒子样式
 */
class MouseMoveSnowflakeStyle extends BaseMouseMoveStyle {
  constructor(possibleArray) {
    super(possibleArray)
    this.possibleArray = ["❄️"]
  }

  addParticle = (x, y, character) => {
    var particle = new SnowflakeParticle()
    particle.init(x, y, character)
    this.particles.push(particle)
  }
}

/**
 * Bubble气泡粒子对象
 */
class BubbleParticle extends BaseParticle {
  constructor(styles) {
    super(styles)
    this.lifeSpan = 250; //ms
    this.initialStyles = {
      "position": "fixed",
      "display": "block",
      "pointerEvents": "none",
      "z-index": "10000000",
      "width": "5px",
      "height": "5px",
      "background": "#e6f1f7",
      "box-shadow": "-1px 0px #6badd3, 0px -1px #6badd3, 1px 0px #3a92c5, 0px 1px #3a92c5",
      "border-radius": "1px",
      "will-change": "transform"
    };
  }

  init = (x, y, character) => {

    this.velocity = {
      x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 10),
      y: (-.4 + (Math.random() * -1))
    };

    this.position = { x: x - 10, y: y - 10 };

    this.element = document.createElement('span');
    this.applyProperties(this.element, this.initialStyles);
    this.update();

    document.getElementById("layout-main").appendChild(this.element)
  };

  update = () => {
    this.position.x += this.velocity.x;
    this.position.y += this.velocity.y;

    // Update velocities
    this.velocity.x += (Math.random() < 0.5 ? -1 : 1) * 2 / 75;
    this.velocity.y -= Math.random() / 600;
    this.lifeSpan--;

    this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px,0) scale(" + (0.2 + (250 - this.lifeSpan) / 250) + ")";
  }
}

/**
 * 鼠标移动气泡粒子样式
 */
class MouseMoveBubbleStyle extends BaseMouseMoveStyle {
  constructor(possibleArray) {
    super(possibleArray)
  }

  addParticle = (x, y, character) => {
    var particle = new BubbleParticle()
    particle.init(x, y, character)
    this.particles.push(particle)
  }
}

/**
 * 设置鼠标点击效果
 * @param {Number} type 效果类型
 */
const setMouseClickStyle = (type) => {
  var mouseStyle = myStore.mouseStyle.getValue();
  if (!mouseStyle) mouseStyle = {}

  var mouseClickStyle = mouseStyle.mouseClickStyle;
  if (mouseClickStyle) {
    mouseClickStyle.destroy()
  }

  if (!type) {
    type = advancedConfigSetting.getData()?.mouseClickStyleMode;
  }

  //
  if (type == 1) {
    mouseClickStyle = new MouseClickTextStyle();
  }
  else if (type == 2) {
    mouseClickStyle = new MouseClickFireworksStyle();
  }
  else {
    mouseClickStyle = new BaseMouseClickStyle();
  }

  if (mouseClickStyle) {
    mouseStyle.mouseClickStyle = mouseClickStyle;
    mouseClickStyle.init();
    myStore.mouseStyle.setValue(mouseStyle);
  }
}

/**
 * 设置鼠标移动效果
 * @param {Number} type 效果类型
 */
const setMouseMoveStyle = (type) => {
  var mouseStyle = myStore.mouseStyle.getValue();
  if (!mouseStyle) mouseStyle = {}
  var mouseMoveStyle = mouseStyle.mouseMoveStyle;
  if (mouseMoveStyle) {
    mouseMoveStyle.destroy()
  }

  if (!type) {
    type = advancedConfigSetting.getData()?.mouseMoveStyleMode;
  }

  //
  if (type == 1) {
    mouseMoveStyle = new MouseMoveSnowflakeStyle();
  }
  else if (type == 2) {
    mouseMoveStyle = new MouseMoveBubbleStyle();
  }
  else if (type == 3) {
    mouseMoveStyle = new MouseMoveFairyDustStyle();
  }
  else {
    mouseMoveStyle = new BaseMouseMoveStyle();
  }

  if (mouseMoveStyle) {
    mouseStyle.mouseMoveStyle = mouseMoveStyle;
    mouseMoveStyle.init();
    myStore.mouseStyle.setValue(mouseStyle);
  }
}

export { setMouseClickStyle, setMouseMoveStyle }